#include "SerialPort.h"
#include <QDebug>

SerialPort::SerialPort(const QString &portName, const QString &devName, QObject *parent, int timeout)
    : QObject(parent),
      m_timeout(timeout),
      m_portName(portName),
      m_devName(devName)
{
    m_serial = new QSerialPort(this);          // 创建串口对象
    m_timeoutTimer = new QTimer(this);         // 创建定时器对象
    m_timeoutTimer->setSingleShot(true);       // 设置定时器为单次触发
}

SerialPort::~SerialPort()
{
    // 关闭串口
    closePort();

    if(m_timeoutTimer != nullptr)
    {
        delete m_timeoutTimer;
    }

    if(m_serial != nullptr)
    {
        delete m_serial;
    }
}

void SerialPort::sendData(const QByteArray &data, std::function<void(const QByteArray&)> parser)
{
    m_sendQueue.enqueue({data, parser});       // 将数据和解析函数加入发送队列
    if (!m_timeoutTimer->isActive()) {         // 如果定时器未激活，则处理下一帧数据
        processNext();
    }
}

void SerialPort::sendStringData(const QString &data, std::function<void(const QByteArray&)> parser)
{
    QByteArray requestData = data.toLatin1();
    m_sendQueue.enqueue({requestData, parser});// 将数据和解析函数加入发送队列
    if (!m_timeoutTimer->isActive()) {         // 如果定时器未激活，则处理下一帧数据
        processNext();
    }
}

void SerialPort::setTimeout(int timeout)
{
    this->m_timeout = timeout;                 // 设置超时时间
}

void SerialPort::configurePort(QSerialPort::BaudRate baudRate, QSerialPort::DataBits dataBits,
                               QSerialPort::Parity parity, QSerialPort::StopBits stopBits,
                               QSerialPort::FlowControl flowControl)
{
    m_serial->setBaudRate(baudRate);           // 设置波特率
    m_serial->setDataBits(dataBits);           // 设置数据位
    m_serial->setParity(parity);               // 设置校验位
    m_serial->setStopBits(stopBits);           // 设置停止位
    m_serial->setFlowControl(flowControl);     // 设置流控
    m_isConfigured = true;                     // 标记串口参数已配置
}

bool SerialPort::openPort(const QString &portName)
{
    // 检查端口是否已经打开
    if (!m_serial->isOpen()) {
        qDebug() << "正在打开串口...";
    } else {
        qDebug() << "串口已打开，已连接成功.";
        return true;
    }

    if(false == m_isConfigured)
    {
        qDebug() << "配置参数未配置，按默认配置打开";
//        qDebug() << "配置参数未配置";
//        return false;
    }

    // 检查端口号是否为空
    if(portName.isEmpty())
    {
        qDebug() << "端口号不能为空";
        return false;
    }

    m_serial->setPortName(portName);
    if(m_serial->open(QIODevice::ReadWrite))
    {
        qDebug() << QString("%1 %2串口已打开").arg(m_devName).arg(m_portName);
        m_connectStatus = true;
        m_openFlag = true;
        return true;
    }

    // 连接信号和槽
    connect(m_serial, &QSerialPort::readyRead, this, &SerialPort::onReadyRead);
    connect(m_timeoutTimer, &QTimer::timeout, this, &SerialPort::onTimeout);
}

void SerialPort::closePort()
{
    m_openFlag = false;
    m_isConfigured = false;

    // 断开信号和槽
    disconnect(m_serial, &QSerialPort::readyRead, this, &SerialPort::onReadyRead);
    disconnect(m_timeoutTimer, &QTimer::timeout, this, &SerialPort::onTimeout);

    if (m_serial->isOpen())                    // 如果串口打开，则关闭串口
        m_serial->close();
}

bool SerialPort::checkConnectState()
{
    return connectStatus();
}

void SerialPort::processNext()
{
    if (m_sendQueue.isEmpty())                 // 如果队列为空，则返回
        return;

    m_currentFrame = m_sendQueue.dequeue();      // 从队列中取出下一帧数据
    m_serial->write(m_currentFrame.data);        // 发送数据
    m_timeoutTimer->start(m_timeout);            // 启动定时器
}

bool SerialPort::connectStatus() const
{
    return m_connectStatus;
}

void SerialPort::setConnectStatus(bool connectStatus)
{
    m_connectStatus = connectStatus;
}

void SerialPort::onReadyRead()
{
    m_timeoutTimer->stop();                    // 停止定时器
    QByteArray responseData = m_serial->readAll(); // 读取所有响应数据
    emit dataReceived(responseData);         // 发射数据接收信号

    // 调用对应的解析函数处理响应数据
    if (m_currentFrame.parser) {
        m_currentFrame.parser(responseData);
    }
    m_connectStatus = true;

    // 继续处理队列中的下一帧数据
    processNext();
}

void SerialPort::onTimeout()
{
    emit responseTimeout(m_currentFrame.data); // 发射响应超时信号

    m_connectStatus = false;

    // 继续处理队列中的下一帧数据
    processNext();
}
